#define _CRT_SECURE_NO_WARNINGS
#include "PngDecoder.h"
#include "stdio.h"

#define LOGD printf
#define LOGE printf

PngDecoder::PngDecoder()
{
}


PngDecoder::~PngDecoder()
{
}

void PngDecoder::readPngData(png_structp pngPtr, png_bytep data, png_size_t length) {
	FILE* file = (FILE*)png_get_io_ptr(pngPtr);
	fread(data, 1, length, file);
}

void* PngDecoder::decoder(const char* filePath, int&texWidth, int&texHeight) {
	void* pixelData = NULL;
	FILE* file = NULL;

	do
	{
		file = fopen(filePath, "rb");

		if (file == NULL) {
			break;
		}

		unsigned char head[8];
		fread(head, 1, 8, file);
		if (png_sig_cmp(head, 0, 8)) {
			LOGE("File %s, is not PNG", filePath);
			break;
		}

		/* Create and initialize the png_struct with the desired error handler
		* functions.  If you want to use the default stderr and longjump method,
		* you can supply NULL for the last three parameters.  We also supply the
		* the compiler header file version, so that we know if the application
		* was compiled with a compatible version of the library.  REQUIRED
		*/
		png_structp pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
		if (!pngPtr) {
			LOGE("Unable to create PNG structure: %s", filePath);
			break;
		}

		// Allocate/initialize the memory for image information.  REQUIRED  
		png_infop infoPtr = png_create_info_struct(pngPtr);

		if (!infoPtr) {
			png_destroy_read_struct(&pngPtr, NULL, NULL);
			LOGE("Unable to create PNG info : %s", filePath);
			break;
		}

		png_infop endInfo = png_create_info_struct(pngPtr);
		if (!endInfo) {
			png_destroy_read_struct(&pngPtr, &infoPtr, NULL);
			LOGE("Unable to create PNG end info : %s", filePath);
			break;
		}

		// Set error handling if you are using the setjmp/longjmp method (this is  
		// the normal method of doing things with libpng).  REQUIRED unless you  
		// set up your own error handlers in the png_create_read_struct() earlier.  
		if (setjmp(png_jmpbuf(pngPtr))) {
			// Free all of the memory associated with the png_ptr and info_ptr  
			png_destroy_read_struct(&pngPtr, &infoPtr, &endInfo);
			LOGE("Error during setjmp : %s", filePath);
			break;
		}

		/* If you are using replacement read functions, instead of calling
		* png_init_io() here you would call:
		* where user_io_ptr is a structure you want available to the callbacks
		*/
		png_set_read_fn(pngPtr, (void*)file, readPngData);

		// If we have already read some of the signature  
		png_set_sig_bytes(pngPtr, 8);

		/* The call to png_read_info() gives us all of the information from the
		* PNG file before the first IDAT (image data chunk).  REQUIRED
		*/
		png_read_info(pngPtr, infoPtr);

		int bitDepth;
		int colorType;
		int interlaceype;

		png_uint_32 width;
		png_uint_32 height;

		png_get_IHDR(pngPtr, infoPtr,
			&width,
			&height,
			&bitDepth, &colorType, &interlaceype, NULL, NULL);

		texWidth = width;
		texHeight = height;

		LOGD("PNG width = %d, height = %d", texWidth, texHeight);

		// Update the png info struct.  
		png_read_update_info(pngPtr, infoPtr);

		// Allocate the memory to hold the image using the fields of info_ptr  

		unsigned int rowBytes = png_get_rowbytes(pngPtr, infoPtr);
		LOGD("Row size: %d bytes", rowBytes);

		// Allocate the pixel data as a big block, to be given to openGL  
		pixelData = png_malloc(pngPtr, rowBytes * height);
		if (!pixelData) {
			png_destroy_read_struct(&pngPtr, &infoPtr, &endInfo);
			LOGE("Unable to allocate PNG pixel data while loading %s", filePath);
			break;
		}

		/* Turn on interlace handling.  REQUIRED if you are not using
		* png_read_image().  To see how to handle interlacing passes,
		* see the png_read_row() method below:
		*/
		int numberPasses = png_set_interlace_handling(pngPtr);
		LOGD("interlacing passes = %d", numberPasses);
		for (int pass = 0; pass < numberPasses; pass++) {
			for (int row = 0; row < height; row++) {
				png_read_row(pngPtr, ((unsigned char*)pixelData + (row * rowBytes)), NULL);
			}
		}

		// Read rest of file, and get additional chunks in info_ptr - REQUIRED  
		png_read_end(pngPtr, infoPtr);

		// At this point you have read the entire image  

		// Clean up after the read, and free any memory allocated - REQUIRE  
		png_destroy_read_struct(&pngPtr, &infoPtr, &endInfo);
	} while (0);

	fclose(file);

	return pixelData;
}


